<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Agent Descriptions JSON-LD 数据可视化工具</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        .scroll-container {
            height: calc(100vh - 120px);
            overflow-y: auto;
            scroll-behavior: smooth;
        }
        
        .scroll-container::-webkit-scrollbar {
            width: 8px;
        }
        
        .scroll-container::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 4px;
        }
        
        .scroll-container::-webkit-scrollbar-thumb {
            background: #888;
            border-radius: 4px;
        }
        
        .scroll-container::-webkit-scrollbar-thumb:hover {
            background: #555;
        }

        .json-content pre {
            margin: 0;
            white-space: pre-wrap;
            word-wrap: break-word;
        }

        .json-url {
            color: #2563eb;
            text-decoration: underline;
            cursor: pointer;
        }

        .json-url:hover {
            color: #1d4ed8;
        }

        .json-key {
            color: #059669;
        }

        .json-string {
            color: #db2777;
        }

        .json-number {
            color: #2563eb;
        }

        .json-boolean {
            color: #7c3aed;
        }

        .json-null {
            color: #6b7280;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- 主页面 -->
    <div id="home-page" class="container mx-auto px-4 py-8">
        <h1 class="text-3xl font-bold text-center mb-8">Agent Descriptions JSON-LD 数据可视化工具</h1>
        <div class="max-w-2xl mx-auto">
            <div class="bg-white rounded-lg shadow-lg p-6">
                <input type="text" 
                       id="jsonld-url" 
                       class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                       placeholder="请输入JSON-LD的URL">
                <button onclick="parseJsonLD()" 
                        class="mt-4 w-full bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors">
                    解析
                </button>
            </div>
        </div>
    </div>

    <!-- 解析页面 -->
    <div id="parse-page" class="hidden min-h-screen">
        <nav class="bg-white shadow-lg">
            <div class="container mx-auto px-4 py-3">
                <button onclick="goBack()" 
                        class="text-gray-600 hover:text-gray-900 flex items-center">
                    <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
                    </svg>
                    返回
                </button>
            </div>
        </nav>
        <div class="container mx-auto px-4 py-6">
            <div class="grid grid-cols-2 gap-6">
                <!-- JSON文本区域 -->
                <div class="bg-white rounded-lg shadow-lg p-6">
                    <div id="json-content" class="scroll-container json-content font-mono text-sm"></div>
                </div>
                <!-- 可视化区域 -->
                <div class="bg-white rounded-lg shadow-lg p-6">
                    <div id="visual-content" class="scroll-container"></div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 存储访问历史
        let history = [];
        let jsonContent;
        let visualContent;
        let isScrolling = false;
        let scrollTimeout;

        // 初始化滚动容器
        document.addEventListener('DOMContentLoaded', () => {
            jsonContent = document.getElementById('json-content');
            visualContent = document.getElementById('visual-content');

            // 处理URL参数
            const urlParams = new URLSearchParams(window.location.search);
            const initialUrl = urlParams.get('url');
            if (initialUrl) {
                document.getElementById('jsonld-url').value = initialUrl;
                showJsonContent(initialUrl);
                // 隐藏首页，显示解析页面
                document.getElementById('home-page').classList.add('hidden');
                document.getElementById('parse-page').classList.remove('hidden');
            }

            // JSON文本滚动时，同步更新右侧展示内容的位置
            jsonContent.addEventListener('scroll', () => {
                if (!isScrolling) {
                    isScrolling = true;
                    clearTimeout(scrollTimeout);

                    const jsonScrollMax = jsonContent.scrollHeight - jsonContent.clientHeight;
                    const visualScrollMax = visualContent.scrollHeight - visualContent.clientHeight;
                    
                    if (jsonScrollMax > 0 && visualScrollMax > 0) {
                        const percentage = jsonContent.scrollTop / jsonScrollMax;
                        visualContent.scrollTop = percentage * visualScrollMax;
                    }

                    scrollTimeout = setTimeout(() => {
                        isScrolling = false;
                    }, 150);
                }
            });
        });

        async function parseJsonLD() {
            const url = document.getElementById('jsonld-url').value;
            if (!url) {
                alert('请输入有效的URL');
                return;
            }

            try {
                // Get base path from current location
                const basePath = window.location.pathname.replace('/jsonld-viewer', '');
                window.location.href = `${basePath}/jsonld-network?url=${encodeURIComponent(url)}`;
            } catch (error) {
                console.error('解析失败：', error);
                alert('解析失败：' + error.message);
            }
        }

        async function showJsonContent(url) {
            try {
                const response = await fetch(url);
                const contentType = response.headers.get('content-type');
                if (contentType && contentType.includes('image/')) {
                    window.open(url, '_blank');
                    return;
                }

                const data = await response.json();
                history.push(url);
                showParsePage(data);
            } catch (error) {
                console.error('解析失败：', error);
                window.open(url, '_blank');
            }
        }

        function showParsePage(data) {
            // 切换页面显示
            document.getElementById('home-page').classList.add('hidden');
            document.getElementById('parse-page').classList.remove('hidden');
            
            // 重置滚动位置
            jsonContent.scrollTop = 0;
            visualContent.scrollTop = 0;
            
            // 显示格式化的JSON文本
            const formattedJson = formatJsonWithLinks(data);
            jsonContent.innerHTML = `<pre>${formattedJson}</pre>`;
            
            // 显示可视化内容
            renderVisualContent(data);

            // 添加点击事件处理
            addJsonClickHandlers();
        }

        function formatJsonWithLinks(obj, indent = 0) {
            const space = '  '.repeat(indent);
            let result = '';

            if (Array.isArray(obj)) {
                result += '[\n';
                obj.forEach((item, index) => {
                    result += space + '  ' + formatJsonWithLinks(item, indent + 1);
                    if (index < obj.length - 1) result += ',';
                    result += '\n';
                });
                result += space + ']';
            } else if (typeof obj === 'object' && obj !== null) {
                result += '{\n';
                const entries = Object.entries(obj);
                entries.forEach(([key, value], index) => {
                    const formattedKey = `<span class="json-key">"${key}"</span>`;
                    result += space + '  ' + formattedKey + ': ';
                    
                    if (key === '@id' || (typeof value === 'string' && (value.startsWith('http') || value.includes('://')))) {
                        // URL类型判断
                        let urlType = 'file';
                        if (value.toLowerCase().endsWith('.json')) {
                            urlType = 'json';
                        } else if (value.toLowerCase().match(/\.(jpg|jpeg|png|gif|bmp|webp|svg)$/)) {
                            urlType = 'image';
                        } else if (value.toLowerCase().match(/\.(pdf|doc|docx|txt|md)$/)) {
                            urlType = 'document';
                        }
                        result += `<span class="json-url" data-url="${value}" data-type="${urlType}">"${value}"</span>`;
                    } else {
                        result += formatJsonWithLinks(value, indent + 1);
                    }
                    
                    if (index < entries.length - 1) result += ',';
                    result += '\n';
                });
                result += space + '}';
            } else if (typeof obj === 'string') {
                result += `<span class="json-string">"${obj}"</span>`;
            } else if (typeof obj === 'number') {
                result += `<span class="json-number">${obj}</span>`;
            } else if (typeof obj === 'boolean') {
                result += `<span class="json-boolean">${obj}</span>`;
            } else if (obj === null) {
                result += `<span class="json-null">null</span>`;
            }

            return result;
        }

        function addJsonClickHandlers() {
            const urlElements = jsonContent.getElementsByClassName('json-url');
            Array.from(urlElements).forEach(element => {
                element.addEventListener('click', (e) => {
                    e.preventDefault();
                    const url = element.dataset.url;
                    handleUrlClick(url);
                });
            });
        }

        function handleUrlClick(url) {
            const urlType = getUrlType(url);
            if (urlType === 'json') {
                document.getElementById('jsonld-url').value = url;
                parseJsonLD();
            } else {
                window.open(url, '_blank');
            }
        }

        function getUrlType(url) {
            const ext = url.split('.').pop().toLowerCase();
            return ext === 'json' ? 'json' : 'other';
        }

        function goBack() {
            // 移除最后一条历史记录
            history.pop();
            
            if (history.length === 0) {
                // 返回主页
                document.getElementById('home-page').classList.remove('hidden');
                document.getElementById('parse-page').classList.add('hidden');
            } else {
                // 加载上一个URL的内容
                document.getElementById('jsonld-url').value = history[history.length - 1];
                parseJsonLD();
            }
        }

        function renderVisualContent(data) {
            const visualContent = document.getElementById('visual-content');
            visualContent.innerHTML = '';

            // 创建可视化内容
            const content = document.createElement('div');
            content.className = 'space-y-4';
            
            // 处理基本信息
            if (data['@type']) {
                addSection(content, '类型', data['@type']);
            }
            
            if (data['@id']) {
                addSection(content, 'ID', createLinkElement(data['@id']));
            }

            // 处理其他属性
            for (const [key, value] of Object.entries(data)) {
                if (!key.startsWith('@') && value !== null && value !== undefined) {
                    if (typeof value === 'object' && !Array.isArray(value)) {
                        addObjectSection(content, key, value);
                    } else if (Array.isArray(value)) {
                        addArraySection(content, key, value);
                    } else {
                        addSection(content, key, value);
                    }
                }
            }

            visualContent.appendChild(content);
        }

        function addSection(parent, title, content) {
            const section = document.createElement('div');
            section.className = 'border-b border-gray-200 pb-4';
            
            const titleEl = document.createElement('h3');
            titleEl.className = 'text-lg font-semibold text-gray-700 mb-2';
            titleEl.textContent = formatTitle(title);
            
            const contentEl = document.createElement('div');
            contentEl.className = 'text-gray-600';
            
            if (typeof content === 'string' && (content.startsWith('http') || content.includes('://'))) {
                contentEl.appendChild(createLinkElement(content));
            } else {
                contentEl.textContent = content;
            }
            
            section.appendChild(titleEl);
            section.appendChild(contentEl);
            parent.appendChild(section);
        }

        function addObjectSection(parent, title, obj) {
            const section = document.createElement('div');
            section.className = 'border-b border-gray-200 pb-4';
            
            const titleEl = document.createElement('h3');
            titleEl.className = 'text-lg font-semibold text-gray-700 mb-2';
            titleEl.textContent = formatTitle(title);
            
            const contentEl = document.createElement('div');
            contentEl.className = 'pl-4 border-l-2 border-gray-200';
            
            for (const [key, value] of Object.entries(obj)) {
                if (!key.startsWith('@') || key === '@id') {
                    const subSection = document.createElement('div');
                    subSection.className = 'mt-2';
                    
                    const subTitle = document.createElement('span');
                    subTitle.className = 'font-medium text-gray-600';
                    subTitle.textContent = formatTitle(key) + ': ';
                    
                    const subContent = document.createElement('span');
                    subContent.className = 'text-gray-600';
                    if (typeof value === 'object') {
                        subContent.textContent = JSON.stringify(value);
                    } else if (typeof value === 'string' && (value.startsWith('http') || value.includes('://'))) {
                        subContent.appendChild(createLinkElement(value));
                    } else {
                        subContent.textContent = value;
                    }
                    
                    subSection.appendChild(subTitle);
                    subSection.appendChild(subContent);
                    contentEl.appendChild(subSection);
                }
            }
            
            section.appendChild(titleEl);
            section.appendChild(contentEl);
            parent.appendChild(section);
        }

        function addArraySection(parent, title, array) {
            const section = document.createElement('div');
            section.className = 'border-b border-gray-200 pb-4';
            
            const titleEl = document.createElement('h3');
            titleEl.className = 'text-lg font-semibold text-gray-700 mb-2';
            titleEl.textContent = formatTitle(title);
            
            const contentEl = document.createElement('div');
            contentEl.className = 'space-y-2 pl-4 border-l-2 border-gray-200';
            
            array.forEach((item, index) => {
                const itemEl = document.createElement('div');
                itemEl.className = 'text-gray-600';
                
                if (typeof item === 'object') {
                    const itemContent = document.createElement('div');
                    itemContent.className = 'pl-2';
                    for (const [key, value] of Object.entries(item)) {
                        if (!key.startsWith('@') || key === '@id') {
                            const property = document.createElement('div');
                            property.className = 'mt-1';
                            const valueHtml = typeof value === 'string' && (value.startsWith('http') || value.includes('://'))
                                ? createLinkElement(value).outerHTML
                                : value;
                            property.innerHTML = `<span class="font-medium">${formatTitle(key)}:</span> ${valueHtml}`;
                            itemContent.appendChild(property);
                        }
                    }
                    itemEl.appendChild(itemContent);
                } else if (typeof item === 'string' && (item.startsWith('http') || item.includes('://'))) {
                    itemEl.appendChild(createLinkElement(item));
                } else {
                    itemEl.textContent = item;
                }
                
                contentEl.appendChild(itemEl);
            });
            
            section.appendChild(titleEl);
            section.appendChild(contentEl);
            parent.appendChild(section);
        }

        function createLinkElement(url) {
            const link = document.createElement('a');
            link.href = '#';
            link.className = 'text-blue-600 hover:text-blue-800 underline cursor-pointer';
            link.textContent = url;
            link.onclick = (e) => {
                e.preventDefault();
                handleUrlClick(url);
            };
            return link;
        }

        function formatTitle(str) {
            return str
                .replace(/([A-Z])/g, ' $1')
                .replace(/^./, (str) => str.toUpperCase())
                .trim();
        }
    </script>
</body>
</html>
